﻿package hapi.ui;

import hapi.flash.util.Ploter;
import flash.MovieClip;
import flash.TextField;
import flash.TextFormat;
import flash.Mouse;
import flash.Stage;
import haxe.Timer;

typedef CursorAnim = {
	var name:String;
	var x:Float;
	var y:Float;
	var movieclip:MovieClip;
}

typedef TipStyle = {
	var format:TextFormat;
	var maxWidth:Float;
	var backgroundColor:Int;
	var backgroundAlpha:Int;
}

typedef TipMovieClip =  { > MovieClip, var tf:TextField; }

class CursorManager   {
	
	private static var inst:CursorManager;
	
	private var currentCursor:MovieClip;
	private var mc:MovieClip;
	private var tip:String;
	private var anims:Hash<CursorAnim>;
	private var tipVisible:Bool;
	private var tipStyle:TipStyle;
	public var defaultTipStyle(default,null):TipStyle;
	private var timer:Timer;
	private var root:MovieClip;
	private var tipMovieClip:TipMovieClip;
	
	private function new() {
		this.anims = new Hash();
		this.tip = "";
		this.tipVisible = false;
		this.root = flash.Lib.current;
		this.timer = new Timer(10);
		this.defaultTipStyle = {
			backgroundColor:0xeeeeee,
			backgroundAlpha:90,
			format:new TextFormat("Arial", 10, 0x222222, false, false, false),
			maxWidth:100.
		};
		timer.run = refresh;
	}
	
	public static function getInstance():CursorManager {
		if ( inst == null )
			inst = new CursorManager();
		return inst;
	}
	
	public function addTip( tip:String, ?delay=800, ?style:TipStyle ) {
		removeTip();
		this.tip = tip;
		this.tipVisible = true;
		this.tipStyle = style == null ? defaultTipStyle : style;
		if ( delay > 0 )
			haxe.Timer.delay( showTip, delay );
		else
			this.showTip();
	}
	
	public function removeTip():Void {
		this.tipVisible = false;
		this.tipMovieClip.removeMovieClip();
		this.tipMovieClip = null;
	}
	
	public function getDisplayFunction( tip:String, delay ) {
		var cm:CursorManager = this;
		return function() {
			cm.addTip( tip, delay );
		}
	}
	
	public function changeCursor( linkageId:String ):Void {
		removeCurrentCursor();
		var depth = root.getNextHighestDepth();
		currentCursor = root.attachMovie( linkageId, "__cursor__", depth );
		Mouse.hide();
		currentCursor._visible = true;
		refreshCursor();
	}
	
	public function restoreDefaultCursor() {
		removeCurrentCursor();
		Mouse.show();
	}
	
	public function addMovieClipAsCursorAnim( name:String, mc:MovieClip, ?x = 0., ?y = 0.):CursorAnim {
		mc._x = root._xmouse + x;
		mc._y = root._ymouse + y;
		var anim = { movieclip:mc, x:x, y:y, name:name };
		anims.set( anim.name, anim);
		return anim;
	}
	
	public function addCursorAnim( linkageId:String, ?x = 0., ?y = 0. ):CursorAnim {
		var depth = root.getNextHighestDepth();
		var mc = root.attachMovie( linkageId, "__cursor__anim__" + linkageId, depth );
		return addMovieClipAsCursorAnim( linkageId, mc, x, y);
	}
	
	public function removeAllAnims():Void {
		for( a in anims ) {
			a.movieclip._visible = false;
			a.movieclip.removeMovieClip();
		}
		anims = new Hash();
	}
	
	public function removeAnim( anim:CursorAnim ):Bool {
		if ( !anims.exists(anim.name) ) {
			return false;
		}else{
			anim.movieclip._visible = false;
			anim.movieclip.removeMovieClip();
			anims.remove( anim.name );
			return true;
		}
	}
	
	public function removeAnimByName( name:String ):Bool {
		if ( !anims.exists(name) ) {
			return false;
		}else{
			return removeAnim(anims.get(name));
		}
	}
	
	private function removeCurrentCursor() {
		currentCursor._visible = false;
		currentCursor.removeMovieClip();
		currentCursor = null;
	}
	
	private function showTip():Void {
		tipMovieClip.removeMovieClip();
		if( this.tipVisible ){
			tipMovieClip = cast root.createEmptyMovieClip("___tip___", root.getNextHighestDepth() );
			tipMovieClip.createTextField("tf", 0, 0, 0, tipStyle.maxWidth, 10 );
			var ploter:Ploter = new Ploter( tipMovieClip );
			ploter.clear();
			ploter.beginFill( this.tipStyle.backgroundColor, this.tipStyle.backgroundAlpha );
			ploter.lineStyle(0, 0x000000, 0 );
			
			var tf = tipMovieClip.tf;
			tf.autoSize = true;
			tf.setNewTextFormat(tipStyle.format);
			tf.selectable = false;
			tf.text = tip;
			if ( tf.textWidth > tipStyle.maxWidth ) {
				tf.multiline = true;
				tf.wordWrap = true;
				tf.text = tip;
			}
			ploter.drawRoundRect( -4, -4, tf._width + 8, tf._height + 8, 8 );
			ploter.endFill();
			ploter.drawRoundGlow( -4, -4, tf._width + 8, tf._height + 8, 8, 5, tipStyle.backgroundColor, tipStyle.backgroundAlpha, 100 );
			refreshTip();
		}
	}
	
	private function refresh() {
		refreshAnims();
		refreshCursor();
		refreshTip();
	}
	
	private function refreshCursor() {
		if( this.currentCursor != null){
			currentCursor._x = root._xmouse;
			currentCursor._y = root._ymouse;
		}
	}
	
	private function refreshAnims() {
		for (a in anims ) {
			a.movieclip._x = root._xmouse + a.x;
			a.movieclip._y = root._ymouse + a.y;
		}
	}
	
	private function refreshTip() {
		if( tipMovieClip != null && tip.length > 0){
			var x = root._xmouse;
			var y = root._ymouse;
			if ( x > Stage.width/2 ) {
				x -= tipMovieClip._width - 5;
			}else{
				x += 10;
			}
			if ( y > Stage.height/2 )
			{
				y -= tipMovieClip.tf._height + 5;
			}else{
				y += 15;
			}
			tipMovieClip._x = x;
			tipMovieClip._y = y;
		}
	}
}